﻿using Leo.Awesome.DictionaryManagement.Domain;
using Leo.Awesome.DictionaryManagement.Dtos;
using Leo.Awesome.DictionaryManagement.Services;
using Leo.Core.Application;
using Leo.Core.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;

namespace Leo.Awesome.DictionaryManagement.Servcies
{
    public class SectionAppService : BaseCrudAppService
        <Section,
        SectionGetOutPutDto,
        SectionGetListOutputDto,
        SectionPagedResultDto,
        Guid,
        SectionGetListInput,
        SectionCreateUpdateInput,
        SectionCreateUpdateInput,
        SectionGetListPageInput
        >, ISectionAppService
    {
        private readonly ISectionRepository mainRepository;

        public SectionAppService(ISectionRepository mainRepository) : base(mainRepository)
        {
            this.mainRepository = mainRepository;
        }

        protected override IQueryable<Section> BuildQuery(SectionGetListInput getListInput, IQueryable<Section> query)
        {
            query = query.WhereIf(!getListInput.Name.IsNullOrWhiteSpace(), x => x.Name.Contains(getListInput.Name));
            return base.BuildQuery(getListInput, query);
        }

        public override async Task<SectionGetOutPutDto> CreateAsync(SectionCreateUpdateInput input)
        {
            await CheckSectionCreateUpdateInput(input);
            await CheckCreatePolicyAsync();
            var entity = await MapToEntityAsync(input);
            if (!input.ParentId.HasValue)
            {
                entity.TreePath = entity.Id.ToString();
            }
            else
            {
                entity.TreePath = await GetNextChildPathCodeAsync(input.ParentId.Value, entity.Id);
            }
            TryToSetTenantId(entity);

            await Repository.InsertAsync(entity, autoSave: true);

            return await MapToGetOutputDtoAsync(entity);
        }

        public virtual async Task<string> GetNextChildPathCodeAsync(Guid parentId, Guid id)
        {
            var entity = await mainRepository.GetAsync(parentId);
            return entity.TreePath + "/" + id;
        }

        public override async Task<SectionGetOutPutDto> UpdateAsync(Guid id, SectionCreateUpdateInput input)
        {
            await CheckSectionCreateUpdateInput(input);
            return await base.UpdateAsync(id, input);
        }
        private async Task CheckSectionCreateUpdateInput(SectionCreateUpdateInput input)
        {
            CheckBusinessErrors(input == null, "参数错误!");
            CheckBusinessErrors(input.Name.IsNullOrWhiteSpace(), "请输入名称");
            CheckBusinessErrors(input.Code.IsNullOrWhiteSpace(), "请输入编码");

            var exist = await mainRepository.AnyAsync(x => x.Code == input.Code
             && x.Id != input.Id);

            CheckBusinessErrors(exist, $"输入的编码【{input.Code}】,已经存在，请重新输入");
        }

        public async Task<List<SectionTreeOutput>> GetTree(SectionTreeInput input)
        {
            var query = await mainRepository.GetQueryableAsync();
            var sections = new List<Section>();
            var outputs = new List<SectionTreeOutput>();
            if (input.Name.IsNullOrWhiteSpace())
            {
                sections = query.ToList();
                outputs = ObjectMapper.Map<List<Section>, List<SectionTreeOutput>>(sections);
                return outputs.ToTree(x => x.Id, x => x.ParentId).ToList();
            }

            query = query.Where(x => x.Name.Contains(input.Name));
            sections = query.ToList();
            var reversedStrs = new List<Guid>();
            foreach (var item in sections)
            {
                if (item.TreePath.IsNullOrWhiteSpace())
                {
                    continue;
                }
                var parts = item.TreePath.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);

                var guidList = parts
                     .Select(x => Guid.TryParse(x, out Guid guid) ? guid : Guid.Empty)
                     .ToList();
                reversedStrs.AddRange(guidList);
            }
            sections = await mainRepository.GetListAsync(x => reversedStrs.Contains(x.Id));
            outputs = ObjectMapper.Map<List<Section>, List<SectionTreeOutput>>(sections);
            return outputs.ToTree(x => x.Id, x => x.ParentId).ToList();
        }
    }
}
